import dayjs from 'dayjs';
import { BaseSystem } from '../base';
import { EVENTS, type IEventBus } from '../../events';
import type { InventoryModel } from '../../model/inventory';
import { ITEM_TYPE } from '../../data/item/type';
import { ItemReader } from '../../systems/item/reader';
import type { PlayerStateSystem } from '../player-state';
import { MODEL_NAME } from '../../constants/model-names';
import type {
  CultivationSkillModel,
  PlayerProgressModel,
  SpiritualRootModel,
  WalletModel,
} from '../../model';
import { ITEM_ID, type ItemConfig } from '../../data/item';
import type {
  InventorySlotInfoItem,
  InventorySlotItem,
  TempSlot,
} from '../../model/inventory/type';
import { CURRENCY_TYPE } from '../../model/wallet';

export class InventorySystem extends BaseSystem {
  private bus: IEventBus;
  private playerStateSystem: PlayerStateSystem;

  constructor(bus: IEventBus, playerStateSystem: PlayerStateSystem) {
    super();
    this.bus = bus;
    this.playerStateSystem = playerStateSystem;

    this.bus.on(EVENTS.INVENTORY_ADD, (defId, amount) => {
      const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
        MODEL_NAME.INVENTORY
      );
      const config = ItemReader.getConfig(defId);
      if (!config) return;
      inventoryModel.addItem(config, amount);
    });

    this.bus.on(EVENTS.INVENTORY_REMOVE, (defId, amount) => {
      const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
        MODEL_NAME.INVENTORY
      );
      inventoryModel.removeItem(defId, amount);
    });

    this.bus.on(EVENTS.INVENTORY_USE, (slotId, itemId, amount) => {
      this.useItem(slotId, itemId, amount);
    });

    this.bus.on(EVENTS.INVENTORY_ADD_EQUIP, (inventorySlotItem) => {
      this.addEquip(inventorySlotItem);
    });

    this.bus.on(EVENTS.INVENTORY_SELL, (inventorySlotItem, amount) => {
      this.sellItem(inventorySlotItem, amount);
    });

    this.bus.on(EVENTS.INVENTORY_TEMPORARY_EXTRACT, (tempSlot) => {
      this.extractTempItem(tempSlot);
    });
  }

  private sellItem(inventorySlotItem: InventorySlotItem, amount: number) {
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    const walletModel = this.playerStateSystem.getModel<WalletModel>(
      MODEL_NAME.WALLET
    );
    if (!inventoryModel || !walletModel) return;
    const itemConfig = ItemReader.getConfig(inventorySlotItem.itemId);
    if (!itemConfig) return;
    const item = inventoryModel.getItem(inventorySlotItem.id);
    if (!item) return;
    if (item.quantity < amount) return;
    const price = amount * itemConfig.basePrice;
    walletModel.addCurrency(CURRENCY_TYPE.SPIRIT_STONE, price);
    inventoryModel.removeItem(inventorySlotItem.id, amount);
    this.bus.emit(EVENTS.INVENTORY_SELL_COMPLETED);
  }

  /** 获取背包格子详情 */
  private getSlotInfo() {
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    const cultivationSkillModel =
      this.playerStateSystem.getModel<CultivationSkillModel>(
        MODEL_NAME.CULTIVATION_SKILL
      );
    if (!inventoryModel || !cultivationSkillModel) return [];
    const items = inventoryModel.getItems();
    const slotInfo = items.map<InventorySlotInfoItem | null>((v) => {
      switch (v.itemConfig.type) {
        case ITEM_TYPE.CULTIVATION_SKILL:
          const isLearned = cultivationSkillModel.isLearned(v.itemConfig.id);
          const canLearn =
            !isLearned &&
            this.playerStateSystem.checkConditions(
              v.itemConfig.studyConditions || []
            );
          const studyConditionProgress =
            this.playerStateSystem.getConditionsProgress(
              v.itemConfig.studyConditions || []
            );
          return {
            ...v,
            itemConfig: v.itemConfig,
            canLearn,
            studyConditionProgress,
            type: ITEM_TYPE.CULTIVATION_SKILL,
          };
        case ITEM_TYPE.EQUIPMENT:
          return {
            ...v,
            itemConfig: v.itemConfig,
            type: ITEM_TYPE.EQUIPMENT,
          };
        case ITEM_TYPE.MATERIAL:
          return {
            ...v,
            itemConfig: v.itemConfig,
            type: ITEM_TYPE.MATERIAL,
          };
        default:
          throw new Error('未知的物品类型');
      }
    });
    const capacity = inventoryModel.getCapacity();
    while (slotInfo.length < capacity) {
      slotInfo.push(null);
    }
    return slotInfo;
  }

  /** 获取临时背包格子详情 */
  private getTempSlotInfo() {
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    if (!inventoryModel) return [];
    return inventoryModel.getTempSlots().map((v) => {
      const expireTime = v.createdAt + inventoryModel.getTempDuration();
      return {
        ...v,
        // 过期时间
        expireTime: dayjs(expireTime).format('YYYY-MM-DD HH:mm:ss'),
        itemConfig: ItemReader.getConfig(v.ins.itemId),
      };
    });
  }

  private useItem(slotId: string, itemId: string, amount: number) {
    const item = ItemReader.getConfig(itemId);
    if (!item) return;
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    const inv = inventoryModel.getItem(slotId);
    if (!inv) return;
    if (inv.quantity < amount) return;
    const itemType = item.type;
    switch (itemType) {
      case ITEM_TYPE.CULTIVATION_SKILL:
        this.useCultivationSkill(slotId, item);
        break;
      default:
        break;
    }
  }

  /** 学习功法 */
  private useCultivationSkill(slotId: string, item: ItemConfig) {
    if (item.type !== ITEM_TYPE.CULTIVATION_SKILL) return;
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    const cultivationSkillModel =
      this.playerStateSystem.getModel<CultivationSkillModel>(
        MODEL_NAME.CULTIVATION_SKILL
      );
    const spiritualRootModel =
      this.playerStateSystem.getModel<SpiritualRootModel>(
        MODEL_NAME.SPIRITUAL_ROOT
      );
    if (!inventoryModel || !cultivationSkillModel || !spiritualRootModel)
      return;
    const skills = cultivationSkillModel.getPlayerSkillsInfo();
    const hasKill = skills.some((v) => {
      return v.skillConfig.id === item.id;
    });
    if (hasKill) return;
    const canLearn = this.playerStateSystem.checkConditions(
      item.studyConditions || []
    );
    if (!canLearn) return;
    inventoryModel.removeItem(slotId, 1);
    cultivationSkillModel.learnSkill(item.id);
    this.bus.emit(EVENTS.INVENTORY_USE_COMPLETED);
  }

  /** 检查是不是已经初始化了灵根且没有学习功法(兼容旧版本) */
  private checkInitedSpiritualRootAndNoCultivationSkill() {
    const playerProgressModel =
      this.playerStateSystem.getModel<PlayerProgressModel>(
        MODEL_NAME.PLAYER_PROGRESS
      );
    const cultivationSkillModel =
      this.playerStateSystem.getModel<CultivationSkillModel>(
        MODEL_NAME.CULTIVATION_SKILL
      );
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    if (!playerProgressModel || !cultivationSkillModel || !inventoryModel)
      return;
    if (!playerProgressModel.initedSpiritualRoot) return;
    if (cultivationSkillModel.getPlayerSkillsInfo().length > 0) return;
    const items = inventoryModel.getItems();
    const cultivationSkillItems = items.filter((v) => {
      return v.itemConfig.type === ITEM_TYPE.CULTIVATION_SKILL;
    });
    if (cultivationSkillItems.length > 0) return;
    const config = ItemReader.getConfig(ITEM_ID.XIAN_TIAN_YI_QI_JUE);
    if (!config) return;
    inventoryModel.addItem(config, 1);
  }

  private addEquip(inventorySlotItem: InventorySlotItem) {
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    if (!inventoryModel) return;
    inventoryModel.addEquip(inventorySlotItem);
  }

  private extractTempItem(tempSlot: TempSlot) {
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    const walletModel = this.playerStateSystem.getModel<WalletModel>(
      MODEL_NAME.WALLET
    );
    if (!inventoryModel) return;
    const isFull = inventoryModel.checkFull();
    if (isFull) {
      this.bus.emit(EVENTS.GAME_MESSAGE, '背包已满，提取失败');
      return;
    }
    inventoryModel.extractTempItem(tempSlot);
    walletModel.spendCurrency(CURRENCY_TYPE.SPIRIT_STONE, 1000);
    this.bus.emit(EVENTS.GAME_MESSAGE, '提取成功');
  }

  public getUISnapshot() {
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    if (!inventoryModel) {
      return {
        slots: [],
        capacity: 0,
        useCapacity: 0,
        tempSlots: [],
      };
    }
    return {
      slots: this.getSlotInfo(),
      capacity: inventoryModel.getCapacity(),
      useCapacity: inventoryModel.getUseCapacity(),
      tempSlots: this.getTempSlotInfo(),
    };
  }

  public override init(): void {
    this.checkInitedSpiritualRootAndNoCultivationSkill();
  }

  public override update(): void {
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    if (!inventoryModel) return;
    inventoryModel.checkTempItemExpired();
  }
}
